package net.angrynut.web.handler.controller;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.annotation.RequestScope;
import org.springframework.web.context.request.async.DeferredResult;

import com.google.common.collect.ImmutableMap;

import net.angrynut.web.configuration.ExceptionHandlers;
import net.angrynut.web.dao.mapper.UserMapper;
import net.angrynut.web.model.entity.User;

/**
 * <p>
 * 这是一些基于注解的 handler 示例。
 * 
 * <p>
 * 注解 {@code @RequestScope} 指出 Bean {@code HelloRestController} 的作用域是
 * {@code request}。实际使用中，使用默认作用域即可。
 */
@RequestScope
@RestController
@RequestMapping("/hello")
public class HelloRestController {

	@Autowired
	private UserMapper userMapper;

	/**
	 * 演示一个普通的 handler。
	 */
	@GetMapping("/world")
	public Map<String, Object> hello() {
		Map<String, Object> map = new HashMap<>();
		map.put("Hello", "World");
		return map;
	}

	/**
	 * 演示 ExceptionHandler 对异常的处理。
	 * 
	 * @see ExceptionHandlers
	 */
	@GetMapping("/except")
	public void exception() {
		throw new RuntimeException("I am capricious.");
	}

	/**
	 * 演示 path variable。如：<tt>http://localhost:8192/hello/path/ss/12</tt>。
	 */
	@GetMapping("/path/{v1}/{v2}")
	public Map<String, Object> path(@PathVariable("v1") String v1, @PathVariable("v2") int v2) {
		return ImmutableMap.of("v1", v1, "v2", v2);
	}

	/**
	 * 演示获取 query string。如：<tt>http://localhost:8192/hello/query?xxx=static</tt>。
	 */
	@GetMapping("/query")
	public Map<String, Object> query(@RequestParam("xxx") String xxx) {
		return ImmutableMap.of("xxx", xxx);
	}

	/**
	 * <p>
	 * 演示获取 request body 和 header。如：
	 * </p>
	 * 
	 * <pre>
	 *  POST http://localhost:8192/hello/login
	 *  Content-Type: application/json; charset=utf-8
	 * 
	 *  {
	 *  	"username" : "Xiao Ming",
	 *  	"password" : "123456"
	 *  }
	 * </pre>
	 */
	@PostMapping("/login")
	public Map<String, Object> login(@RequestBody User user, @RequestHeader("Content-Type") String contentType) {
		return ImmutableMap.of("user", user, "contentType", contentType);
	}

	/**
	 * 异步请求之 <tt>Callable</tt>。
	 */
	@GetMapping("/callable")
	public Callable<Map<String, Object>> callable() {
		Map<String, Object> map = new HashMap<>();
		map.put("ThreadId1", Thread.currentThread().getId());
		return () -> {
			Thread.sleep(3000);
			map.put("ThreadId2", Thread.currentThread().getId());
			return map;
		};
	}

	/**
	 * 异步请求之 <tt>DeferredResult</tt>。
	 */
	@GetMapping("/deferred-result")
	public DeferredResult<Map<String, Object>> quotes() {
		DeferredResult<Map<String, Object>> deferredResult = new DeferredResult<>();
		Map<String, Object> map = new HashMap<>();
		map.put("ThreadId1", Thread.currentThread().getId());
		new Thread(() -> {
			try {
				Thread.sleep(3000);
				map.put("ThreadId2", Thread.currentThread().getId());
				deferredResult.setResult(map);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}).start();

		return deferredResult;
	}

	/**
	 * 演示 Mybatis 的使用。
	 */
	@GetMapping("/mybatis")
	public List<User> mybatis() {
		return Arrays.asList(userMapper.findByUsername("admin"), userMapper.findById(1L));
	}

}